﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;

public class MCNetSocket : MonoBehaviour {
    public static MCNetSocket instance;
    public Queue taskQues =Queue.Synchronized( new Queue());//sync,线程安全性。主线程用于刷新ui的任务队列,只存放action
    public Text ipport;
    public Text sendm;
    public Text screen;//printf msg to the screen 
    public Image btn;
    public static Socket client;
    public static Socket server;
    public static ClientList conns=new ClientList();
    public int selectShower = 0;//当前显示数据的微机
    public delegate void RecMethod(byte[] bs,int count);
    public static event RecMethod OnRec;//接受到的数据和长度，在主线程中发布事件
    private byte[] recdata = new byte[1024];
    // Use this for initialization
    private void Awake()
    {
        instance = this;
    }
    void Start () {
        
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress ipaddr =
                (from ipd in ipHostInfo.AddressList
                where ipd.AddressFamily == AddressFamily.InterNetwork//筛选出ipv4的地址
                select ipd).ToArray()[0];//
            EndPoint po = new IPEndPoint(ipaddr, 19132);
            server.Bind(po);
            screen.text = "server ip:" + ipaddr.ToString() + "port:" + "19132.\nlistening";
            new Thread(Listening).Start();
            print("ser started");
        }
        catch (Exception e)
        {
            print(e.Message);
            screen.text = e.Message;
        }
        // new Thread(NetAct).Start();
    }

    public void AsyConnect()
    {
        if (client.Connected)//已经连接，再连接不做处理
        {
            return;
        }
        new Thread(Connect).Start();
    }

    public void SendM()
    {
        try
        {
            BroadCast(sendm.text);
        }
        catch (Exception e)
        {
            print(e.Message);
            taskQues.Enqueue(new Action(() => BtnColor(false)));
        }
        if (!client.Connected) { print("not connect"); return; }
        client.Send(Encoding.ASCII.GetBytes(sendm.text));
    }

    /// <summary>
    /// 向连接的所有client发送数据
    /// </summary>
    /// <param name="msg"></param>
    public static void BroadCast(string msg)
    {
        for (int i = 0; i < conns.Count; i++)
        {

            try
            {
                conns[i].Send(Encoding.ASCII.GetBytes(msg));
            } 
            catch (Exception e)
            {
                conns.Remove(i);
                instance.ScreenShowTask(e.Message);
            }
        }
    }

    /// <summary>
    /// 接受服务端数据
    /// </summary>
    void ReceiveM()
    {
        int count = client.Receive(recdata);
        RecBroadcast(count);
    }

    /// <summary>
    /// 广播收到的数据
    /// </summary>
    /// <param name="count">数据长度</param>
    private void RecBroadcast(int count)
    {
        taskQues.Enqueue(new Action(() => {
            if (OnRec != null)
                OnRec(recdata, count);
        }));
    }

    /// <summary>
    /// 建立与目标端口的连接
    /// </summary>
	void Connect()
    {
        
        try
        {
            string[] s = ipport.text.Split(new char[] { ':' });
        foreach (var i in s)
        {
            print(i);
        }
            IPEndPoint ipen = new IPEndPoint(IPAddress.Parse(s[0]), int.Parse(s[1]));
            client.Connect(ipen);
            print("conneted remote ser");
            taskQues.Enqueue(new Action( ()=>BtnColor(true)));
            while (true)
            {
                ReceiveM();
            }

        }
        catch (Exception e)
        {
            print(e.Message);
            taskQues.Enqueue(new Action( ()=> { BtnColor(false); }));
            ScreenShowTask(e.Message);

        }
    }
    /// <summary>
    /// 改变按钮颜色
    /// </summary>
    /// <param name="active"></param>
    void BtnColor(bool active)
    {
        if (active)
        {
            btn.color = Color.green;
        }
        else
        {
            btn.color = Color.white;
        }
    }

    private void Update()
    {
        if (taskQues.Count>0)
        {
            lock (taskQues)
            {
                Action act= (Action)taskQues.Dequeue();
                act();
            }
        }
        if (Input.GetKeyDown(KeyCode.Escape))
            Application.Quit();
    }

    private void Listening()
    {
        server.Listen(10);
        while (true)
        {
            try
            {
                print("wait for client");
                Socket recClient = server.Accept();
                conns.Add(recClient);
                taskQues.Enqueue(new Action(() =>
                {
                    screen.text = recClient.RemoteEndPoint.ToString() + "connected";
                }));
                new Thread(Receive).Start(recClient);
            }
            catch (Exception e)
            {
                print(e.Message);
                taskQues.Enqueue(new Action(() => BtnColor(false)));
            }
        }
    }
    /// <summary>
    /// 接受客户端数据
    /// </summary>
    /// <param name="o"></param>
    private void Receive(object o)
    {
        Socket clt = (Socket)o;
        try
        {
            while (true)
            {
                int recCount = clt.Receive(recdata);
                if (recCount == 0) return;
                print("current socket " + clt.GetHashCode() + ",select n:" + selectShower + ",select socket:" + conns[selectShower].GetHashCode());
                if (clt == conns[selectShower])//如果是选中的那个客户端发的数据，则广播
                RecBroadcast(recCount);
                print("rec" + clt.RemoteEndPoint.ToString());
            }
        }
        catch (Exception e)
        {
            //screen.text = e.Message;    
            print(e.Message);
            conns.Remove(clt);
        }
    }

    private void OnDestroy()
    {
        server.Dispose();
        client.Dispose();
    }


    /// <summary>
    /// 增加一个在主线程执行的task
    /// </summary>
    /// <param name="action"></param>
    public void AddTask(Action action)
    {
        taskQues.Enqueue(action);
    }
    public static void sAddTask(Action action)
    {
        instance.taskQues.Enqueue(action);
    }
    /// <summary>
    /// 发布一个屏幕显示的task
    /// </summary>
    /// <param name="text"></param>
    public void ScreenShowTask(string text)
    {
        taskQues.Enqueue(new Action(() =>
        {
            screen.text = text;
        }));
    }
}


/// <summary>
/// 封装List<Socket>，用于管理连接的用户
/// </summary>
public class ClientList
{
    public Socket this[int index]
    {
        get { return conns[index]; }
        set { conns[index] = value; }
    }
    private List<Socket> conns=new List<Socket>();
    public int Count
    {
        get { return conns.Count; }
    }
    public List<Socket> Conns
    {
        get
        {
            return conns;
        }
    }

    public event Action OnClientChanges;
    
    public void Add(Socket s)
    {
        conns.Add(s);
        CallEvent();
    }
    public void Remove(Socket s)
    {
        conns.Remove(s);
        CallEvent();
    }
    public void Remove(int index)
    {
        Remove(conns[index]);
    }

    /// <summary>
    /// 刷新列表。将已经断开连接的剔除 
    /// </summary>
    public void FreshList()
    {
        int i = conns.Count;
        while (--i>=0)
        {
            if (!conns[i].Connected)
            {
                Remove(conns[i]);
            }

        }
       


    }
    public List<String> GetNameList()
    {
        List<String> ips =new List<string>();
        foreach (var s in conns)
        {
            ips.Add(s.RemoteEndPoint.ToString());
        }
        return ips;

    }

    private void CallEvent()
    {
        MCNetSocket.sAddTask(()=> {
        if (OnClientChanges != null) OnClientChanges();
        });
    }
}
